package net.d2dcloud.core.aop;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import net.d2dcloud.core.constants.RequestContext;
import net.d2dcloud.core.ex.BizException;
import net.d2dcloud.core.resp.Resp;
import net.d2dcloud.core.resp.RetCode;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 日志切面
 *
 * @author hunsy
 */
@Slf4j
public abstract class BaseWebLogAspect {

  private ThreadLocal<Map<String, Object>> info = new ThreadLocal<> ();

  /**
   * 切点方法
   */
  public abstract void webLog();


  @Around("webLog()")
  public Object around(ProceedingJoinPoint point) {

    try {
      Map<String, Object> map = new HashMap<> (10);
      ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes ();
      HttpServletRequest request = attributes.getRequest ();

      String uri = request.getRequestURI ();
      log.info ("url:{}", uri);

      // 记录下请求内容
      map.put ("url", request.getRequestURL ().toString ());
      map.put ("path", request.getRequestURI ());
      map.put ("method", request.getMethod ());
      map.put ("ip", request.getRemoteAddr ());
      map.put ("class", point.getSignature ().getDeclaringTypeName () + "" + point.getSignature ().getName ());
      Object[] args = point.getArgs ();
      List list = new ArrayList ();
      for (int i = 0; i < args.length; i++) {
        if (args[i] instanceof HttpServletRequest
          || args[i] instanceof HttpServletResponse
          || args[i] instanceof StandardMultipartHttpServletRequest
          || args[i] instanceof MultipartFile) {
        } else {
          list.add (i, args[i]);
        }
      }
      map.put ("args", list);
      Map<String, String> headMap = new HashMap<> (5);
      Enumeration<String> headers = request.getHeaderNames ();
      while (headers.hasMoreElements ()) {
        String name = headers.nextElement ();
        String val = request.getHeader (name);
        headMap.put (name, val);
      }
      map.put ("headers", headMap);
      info.set (map);
      Object object = point.proceed ();
      return new Resp (RetCode.SUCCESS.getCode (), RetCode.SUCCESS.getMsg (), object);
    } catch (Throwable throwable) {
      throwable.printStackTrace ();
      if (throwable instanceof BizException) {
        BizException bizException = (BizException) throwable;
        return new Resp (bizException.getCode (), bizException.getMsg (), null);
      } else {
        return new Resp (RetCode.SYSTEM_ERROR.getCode (), RetCode.SYSTEM_ERROR.getMsg (), null);
      }
    }
  }

  @AfterReturning(value = "webLog()", returning = "retVal")
  public void afterRet(Object retVal) {
    Map<String, Object> map = info.get ();
    map.put ("result", retVal);
    log.info ("resp:{}", JSON.toJSONString (map));
    RequestContext.remove ();
    info.remove ();
  }
}
